package com.atguigu.security.filter;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.jwt.JwtHelper;
import com.atguigu.common.result.Result;
import com.atguigu.common.result.ResultCodeEnum;
import com.atguigu.common.utils.ResponseUtil;
import com.atguigu.model.system.SysUser;
import com.atguigu.security.custom.CustomUser;
import com.atguigu.vo.system.LoginVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private RedisTemplate redisTemplate;

    public TokenLoginFilter(AuthenticationManager authenticationManager,
                            RedisTemplate redisTemplate){
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false);
        this.redisTemplate = redisTemplate;
        //设置登录的接口地址
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(
                "/admin/system/index/login","POST"));
    }

    //重写认证方法
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
            HttpServletResponse response) throws AuthenticationException {
        try{
            //获取用户信息
            LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(),LoginVo.class);
            //封装Authentication对象
            Authentication authentication = new UsernamePasswordAuthenticationToken(loginVo.getUsername(),loginVo.getPassword());
            //调用AuthenticationManager的认证方法
            return this.getAuthenticationManager().authenticate(authentication);
        }catch(IOException e){
            throw new RuntimeException(e);
        }
    }

    //重写认证成功调用的方法
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain,
            Authentication auth) throws IOException, ServletException {
        //首先从认证对象中获取用户对象
        CustomUser principal = (CustomUser)auth.getPrincipal();
        //生成token
        SysUser user = principal.getSysUser();
        String token = JwtHelper.createToken(user.getId(), user.getUsername());

        //获取当前用户的权限数据，并存入redis
        redisTemplate.opsForValue().set(user.getUsername(),
                JSON.toJSONString(auth.getAuthorities()));

        //返回
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //将认证成功的对象添加到spring security上下文中
//        SecurityContextHolder.getContext().setAuthentication(auth);
        ResponseUtil.out(response, Result.ok(map));
    }

    //重写认证失败调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {
        ResponseUtil.out(response,Result.build(null, ResultCodeEnum.LOGIN_ERROR));
    }
}
